#include "user_main.h"

#include "nvs_flash.h"
#include "nvs.h"

static const char *TAG = "global";

#if SUPPORT_FIRMWARE_OTA
static const char *ota_version_url = "http://norep.gitee.io/ota/ota_test/version";
static const char *ota_image_url = "http://norep.gitee.io/ota/ota_test/ota.bin";
#endif

static const char *temperature_sensor_config_topic="homeassistant/sensor/P1T/config";
static const char *temperature_sensor_config_payload="{\"device_class\":\"temperature\",\"name\":\"P1Temperature\",\"unique_id\":\"P1Temperature\",\"state_topic\":\"homeassistant/sensor/P1/state\",\"unit_of_measurement\":\"C\",\"value_template\":\"{{ value_json.temperature}}\"}";

static const char *humidity_sensor_config_topic="homeassistant/sensor/P1H/config";
static const char *humidity_sensor_config_payload="{\"device_class\":\"humidity\",\"name\":\"P1Humidity\",\"unique_id\":\"P1Humidity\",\"state_topic\":\"homeassistant/sensor/P1/state\",\"unit_of_measurement\":\"%\",\"value_template\":\"{{ value_json.humidity}}\"}";

static const char *update_data_topic = "homeassistant/sensor/P1/state";

static AHT20_data_t g_TH_data = {0};

static int user_get_cb(httpd_req_t *req)
{
    httpd_resp_send(req, index_html_start, index_html_end - index_html_start);
    return 0;
}

static int user_post_cb(httpd_req_t *req, char *content, int len)
{
    system_status_t *sys_sta = get_sys_sta();
    char ssid[32];
    char passwd[32];
    int ret = httpd_query_key_value(content,"ssid",ssid,sizeof(ssid));
    if(ret == ESP_OK) {
        printf("ssid = %s\n",ssid);
    }
    else {
        printf("error = %d\n",ret);
    }

    ret = httpd_query_key_value(content,"password",passwd,sizeof(passwd));
    if(ret == ESP_OK) {
        printf("password = %s\n",passwd);
    }
    else {
        printf("error = %d\n",ret);
    }

    if (strlen(ssid) && strlen(passwd)) {
        my_nvs_wifi_info_set(ssid, passwd);
    }
    httpd_resp_send(req, save_html_start, save_html_end - save_html_start);
    sys_sta->reboot_flag = 1;
    return 0;
}

static int shortdown(void)
{
    ESP_LOGW(TAG, "===== SHOART DOWN =====");
    return 0;
}
    
static int longdown(void)
{
    ESP_LOGW(TAG, "===== LONG DOWN =====");
    return 0;
}

static void WIFI_Connect_cb(char *ip)
{
    system_status_t *sys_sta = get_sys_sta();
    sys_sta->network_sta = 1;
    ESP_LOGW(TAG, "wifi connect : %s", ip);
}

static void WIFI_Disconnect_cb(void)
{
    system_status_t *sys_sta = get_sys_sta();
    sys_sta->network_sta = 0;
    ESP_LOGW(TAG, "wifi disconnect");
}

static void WIFI_AP_STAConnect_cb(void)
{
    ESP_LOGW(TAG, "WIFI_AP_STAConnect_cb");

    my_http_cb_t user_cb;
    user_cb.get_cb = user_get_cb;
    user_cb.post_cb = user_post_cb;
    my_http_server_set_callback(user_cb);
    ESP_LOGW(TAG, "Starting webserver");
    my_start_webserver();

}

static void WIFI_AP_STADisconnect_cb(void)
{
    ESP_LOGW(TAG, "WIFI_AP_STADisconnect_cb");
}

static void Networl_init(void)
{
    my_wifi_t wifi_info = {};
    wifi_mode_t wifi_init_mode = WIFI_MODE_AP;

    if (my_nvs_wifi_info_get(&wifi_info)) {

        memset(&wifi_info, 0, sizeof(wifi_info));
        memcpy(wifi_info.ssid, DEFAULT_AP_MODE_SSID, strlen(DEFAULT_AP_MODE_SSID));

        if (strlen(DEFAULT_AP_MODE_PASSWORD) > 0) {
            memmove(wifi_info.password, DEFAULT_AP_MODE_PASSWORD, strlen(DEFAULT_AP_MODE_PASSWORD));
        }

        wifi_info.max_connection = 1;

        wifi_info.ap_staconnect_cb = WIFI_AP_STAConnect_cb;
        wifi_info.ap_stadisconnect_cb = WIFI_AP_STADisconnect_cb;

        wifi_init_mode = WIFI_MODE_AP;
    } else {
        wifi_info.connect_cb = WIFI_Connect_cb;
        wifi_info.disconnect_cb = WIFI_Disconnect_cb;

        wifi_init_mode = WIFI_MODE_STA;
    }
    my_wifi_init(&wifi_info, wifi_init_mode);
}

static void MY_MQTT_Connect_cb(void)
{
    printf("MQTT Connect SUCCESS\n");
    my_mqtt_publish(temperature_sensor_config_topic, temperature_sensor_config_payload, 0, 1, 1);
    my_mqtt_publish(humidity_sensor_config_topic, humidity_sensor_config_payload, 0, 1, 1);
}

static void MY_MQTT_DISConnect_cb(void)
{
}

static void MY_MQTT_RecData_cb(char *topic, int topic_len, char *data, int data_len)
{
}

static void init_my_mqtt()
{
    my_mqtt_init_info_t mqtt_init_cfg = {0};

    mqtt_init_cfg.host = "pi.oynote.top";
    mqtt_init_cfg.port = 1883;
    mqtt_init_cfg.connect_cb = MY_MQTT_Connect_cb;
    mqtt_init_cfg.disconnect_cb = MY_MQTT_DISConnect_cb;
    mqtt_init_cfg.received_cb = MY_MQTT_RecData_cb;

    my_mqtt_init(mqtt_init_cfg);
}

static void mqtt_task(void *arg)
{
    system_status_t *sys_sta = get_sys_sta();
    while (sys_sta->network_sta != 1)
    {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    init_my_mqtt();

    char buf[256];

    while (1)
    {
        while (sys_sta->network_sta)
        {
            memset(buf, 0, sizeof(buf));

            snprintf(buf, sizeof(buf), "{\"temperature\":%.2f,\"humidity\":%.2f}", g_TH_data.Temp, g_TH_data.RH);
            printf("buf:%s\n", buf);
            my_mqtt_publish(update_data_topic, buf, 0, 0, 0);

            vTaskDelay(5000 / portTICK_PERIOD_MS);
        }
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

static void AHT20_delay_ms_cb(uint32_t ms)
{
    vTaskDelay(ms / portTICK_RATE_MS);
}

#define ACK_CHECK_EN     0x1 /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS    0x0 /*!< I2C master will not check ack from slave */
#define ACK_VAL          0x0 /*!< I2C ack value */
#define NACK_VAL         0x1 /*!< I2C nack value */
#define LAST_NACK_VAL    0x2 /*!< I2C last_nack value */

static void IIC_Write_Data(uint8_t dev_addr, uint8_t reg_addr, const uint8_t *data, uint16_t len)
{
    i2c_cmd_handle_t hi2c = i2c_cmd_link_create();
    i2c_master_start(hi2c);
    i2c_master_write_byte(hi2c, dev_addr, ACK_CHECK_EN);
    i2c_master_write_byte(hi2c, reg_addr, ACK_CHECK_EN);
    i2c_master_write(hi2c, (uint8_t *)data, len, ACK_CHECK_EN);
    i2c_master_stop(hi2c);
    i2c_master_cmd_begin(I2C_NUM_0, hi2c, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(hi2c);
}

static void IIC_Read_Data(uint8_t dev_addr,  uint8_t reg_addr, const uint8_t *data, uint16_t len)
{
    i2c_cmd_handle_t hi2c = i2c_cmd_link_create();
    i2c_master_start(hi2c);

    i2c_master_write_byte(hi2c, dev_addr, ACK_CHECK_EN);
    i2c_master_read(hi2c, (uint8_t *)data, len, LAST_NACK_VAL);
    i2c_master_stop(hi2c);
    i2c_master_cmd_begin(I2C_NUM_0, hi2c, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(hi2c);
}

static int user_Aht20_init(void)
{
    AHT20_init_t aht20_init = {0};
    aht20_init.iic_addr = ATH20_SLAVE_ADDRESS;
    aht20_init.wd_cb = IIC_Write_Data;
    aht20_init.rd_cb = IIC_Read_Data;
    aht20_init.delay_ms_cb = AHT20_delay_ms_cb;

    return AHT_Init(aht20_init);
}

static void task1(void *arg)
{
    i2c_config_t i2c_conf;
    i2c_conf.mode = I2C_MODE_MASTER;
    i2c_conf.sda_io_num = GPIO_NUM_2;
    i2c_conf.sda_pullup_en = 1;
    i2c_conf.scl_io_num = GPIO_NUM_14;
    i2c_conf.scl_pullup_en = 1;
    i2c_conf.clk_stretch_tick = 300; // 300 ticks, Clock stretch is about 210us, you can make changes according to the actual situation.

    ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM_0, i2c_conf.mode));
    ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &i2c_conf));

    if (user_Aht20_init()) {
        printf("AHT20 init failed\n");
    }

    while (1)
    {
        if (AHT20_ReadHT(&g_TH_data)) {
            printf("AHT20 read failed\n");
        } else {
            // printf("AHT20 T:%.2f H:%.2f\n", g_TH_data.Temp, g_TH_data.RH);
        }
        vTaskDelay(500 / portTICK_RATE_MS);
    }
    vTaskDelete(NULL);
}

void app_main()
{
    system_status_t *sys_sta = get_sys_sta();
    const esp_app_desc_t *app_desc = esp_ota_get_app_description();
    sys_sta->version = (char *)app_desc->version;
    ESP_LOGI(TAG, "app_version:%s", sys_sta->version); 

#if SUPPORT_FIRMWARE_OTA
    sys_sta->ota_version_path = ota_version_url;
    sys_sta->ota_image_path = ota_image_url;
#endif

    system_init();

    printf("free_heap_size: %d KB\n", esp_get_free_heap_size() / 1024);
    printf("minimum_free_heap_size: %d KB\n", esp_get_minimum_free_heap_size() / 1024);

    set_key_shortDown_callback(200, shortdown);
    set_key_longDown_callback(2000, longdown);
    
    ESP_LOGI(TAG, "start connect wifi...");
    Networl_init();

    ESP_LOGI(TAG,"create update mqtt task");
    new_task(mqtt_task, "mqtt_task", 1024 * 4, NULL, 25);

    xTaskCreate(task1, "task1", 2048, NULL, 20, NULL);
}
